#include "ql.h"  
#include "basisswap.h"
#include "singlefloatingleg.h"
#include "singlefixedleg.h"
#include "fixedratebondwrap.h"
#include "floatingratebondwrap.h"
#include "zerocouponbondwrap.h"
#include "fixedratebondforwardwrap.h"
#include <ql/quantlib.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/unordered_map.hpp>
#include <boost/algorithm/string.hpp>
#include <vector>
#include <sstream>

using boost::assign::map_list_of;
using namespace QuantLib;
using namespace std;

const boost::unordered_map<std::string, TimeUnit>  TU = map_list_of("Days", Days)("D", Days)("d", Days)("Weeks", Weeks)("W", Weeks)("w", Weeks)("Months", Months)("M", Months)("m", Months)("Years", Years)("Y", Years)("y", Years);

//nasty will change useful at this stage for spreadsheet returns
std::string ValueTrade(Instrument* trade, std::vector<std::string> controlStrings);
std::string ValueVanillaSwap(Instrument* trade, std::vector<std::string> controlStrings);
std::string ValueBasisSwap(Instrument* trade, std::vector<std::string> controlStrings);
std::string ValueSingleFloatingLeg(Instrument* trade, std::vector<std::string> controlStrings);
std::string ValueSingleFixedLeg(Instrument* trade, std::vector<std::string> controlStrings);
std::string ValueForwardRateAgreement(Instrument* trade, std::vector<std::string> controlStrings);
std::string ValueSwaption(Instrument* trade, std::vector<std::string> controlStrings);
std::string ValueCreditDefaultSwap(Instrument* trade, std::vector<std::string> controlStrings);
std::string ValueUnknown(Instrument* trade, std::vector<std::string> controlStrings);
std::string ValueZeroCouponBond(Instrument* trade, std::vector<std::string> controlStrings);
std::string ValueFloatingRateBond(Instrument* trade, std::vector<std::string> controlStrings);
std::string ValueFixedRateBond(Instrument* trade, std::vector<std::string> controlStrings);
std::string ValueRepo(Instrument* trade, std::vector<std::string> controlStrings);

std::string SwapEngine(std::string marketName, std::string curveName, std::string discountCurveName);
std::string BondEngine(std::string marketName, std::string curveName, std::string discountCurveName);
std::string DefaultEngine(std::string marketName, std::string curveName, std::string discountCurveName, double recoveryRate);

std::string SwaptionG2Engines(std::string marketName, std::string curveName, std::string volSurfName, double range, int intervals);
std::string SwaptionHW1Engines(std::string marketName, std::string curveName, std::string volSurfName);
std::string SwaptionHW2Engines(std::string marketName, std::string curveName, std::string volSurfName, int steps);
std::string SwaptionBKEngines(std::string marketName, std::string curveName, std::string volSurfName, int steps);

Handle<Quote> setQuote(std::string market, std::string name, double rate);
QuantLib::Period getPeriod(std::string period);

//all quotes
map<std::string, map<std::string, RelinkableHandle<QuantLib::SimpleQuote>>> quotes;
map<std::string, map<std::string, RelinkableHandle<QuantLib::YieldTermStructure>>> relinkableYts;

//all relate to markets, first key market name second key handle to market component
map<std::string, map<std::string, boost::shared_ptr<QuantLib::PricingEngine>>> pricingEngines;
map<std::string, map<std::string, boost::shared_ptr<IborIndex>>> indexs;

map<std::string, map<std::string, boost::shared_ptr<QuantLib::YieldTermStructure>>> rateCurves;
map<std::string, map<std::string, boost::shared_ptr<QuantLib::RateHelper>>> rateHelpers; //rates used in yield and bond curves 

map<std::string, map<std::string, std::vector<boost::shared_ptr<CalibrationHelper>>>> vsurfCalibHelpers; //vsurf
map<std::string, map<std::string, std::vector<QuantLib::Period>>> vsurfPeriodLabels; //vsurf labels
map<std::string, map<std::string, std::vector<QuantLib::Period>>> vsurfMaturityLabels; //vsurf labels
map<std::string, map<std::string, std::vector<double>>> vsurfMarketVols; //vsurf labels

map<std::string, map<std::string, boost::shared_ptr<QuantLib::TermStructureConsistentModel>>> vsurfModels; //vsurf model

map<std::string, map<std::string, boost::shared_ptr<QuantLib::PiecewiseDefaultCurve<HazardRate, BackwardFlat>>>> defaultCurves;
map<std::string, map<std::string, boost::shared_ptr<QuantLib::DefaultProbabilityHelper>>> defaultHelpers; //spreads used in default curves 

map<std::string, map<std::string, boost::shared_ptr<QuantLib::Bond>>> bonds;
map<std::string, map<std::string, boost::shared_ptr<QuantLib::Forward>>> fwdBonds;

//cache related
map<std::string, map<std::string, boost::shared_ptr<QuantLib::Instrument>>> caches; //note intruments used as trades 
map<std::string, map<std::string, std::string>> tradeEngineMap; //links trades to curves to engines

ql::ql(void){}  

ql::~ql(void){}  

//boost::shared_ptr<QuantLib::YieldTermStructure> ql::GetYts(std::string marketName, std::string curveName)
//{
//	boost::shared_ptr<YieldTermStructure> c = rateCurves[marketName][curveName];
//	return c;
//}
//boost::shared_ptr<QuantLib::PricingEngine> ql::GetEngine(std::string marketName, std::string engineName)
//{
//	boost::shared_ptr<QuantLib::PricingEngine> c = pricingEngines[marketName][engineName];
//	return c;
//}
//boost::shared_ptr<QuantLib::Bond> ql::GetBond(std::string marketName, std::string bondName)
//{
//	boost::shared_ptr<QuantLib::Bond> c = bonds[marketName][bondName];
//	return c;
//}
//boost::shared_ptr<QuantLib::Instrument> ql::GetTrade(std::string cacheName, std::string tradeId)
//{
//	boost::shared_ptr<QuantLib::Instrument> c = caches[cacheName][tradeId];
//	return c;
//}

//static
std::vector<std::string> stringToVector(std::string s1)
{
		std::vector<std::string> v;
		boost::split(v, s1, boost::is_any_of(","), boost::token_compress_on);
		return v;
}

std::vector<std::string> stringToDateVector(std::string s1)
{
		std::vector<std::string> v;
		boost::split(v, s1, boost::is_any_of(","), boost::token_compress_on);
		return v;
}

std::vector<std::vector<std::string>> stringTo2DVector(std::string s1)
{
		std::vector<std::string> v1;
		std::vector<std::vector<std::string>> v2;
		boost::split(v1, s1, boost::is_any_of(";"), boost::token_compress_on);
	    for each(std::string s2 in v1)
		{ 
			std::vector<std::string> v;
			boost::split(v, s2, boost::is_any_of(","), boost::token_compress_on);
			v2.push_back(v);
		}
		return v2;
}

Handle<Quote> setQuote(string market, string name, double rate)
{
	//not sure about the relinkable handle at this running all quotes through here
	//RelinkableHandle<QuantLib::SimpleQuote> quote = quotes[market][name];
	//quote->setValue(rate);
	//quote->notifyObservers()

	return Handle<Quote>(new SimpleQuote(rate));
}

QuantLib::Period getPeriod(std::string period)
{
	try
	{
		if (!period.empty())
		{
			stringstream t;
			t <<  *period.rbegin();
			if (period.size() > 1)  
			{
				period.resize(period.size()-1);
				int n = std::stoi(period);
				return n*TU.at(t.str());
			}
		}
		return 0*TU.at("Days");
	}
	catch (...) 
	{ 
		return 0*TU.at("Days");
	}
}

QuantLib::DayCounter DayCount(std::string dayCount)
{
	if(dayCount == "30/360:BondBasis") return Thirty360(Thirty360::BondBasis);
	else if(dayCount == "Euro30/360")return Thirty360(Thirty360::European); 
	else if(dayCount == "Act/360")	return Actual360(); 
	else if(dayCount == "Act/365:Fixed")  return Actual365Fixed();
	else if(dayCount == "Act/Act:ISDA") return ActualActual(ActualActual::ISDA);
    else if(dayCount == "Act/Act:Bond") return ActualActual(ActualActual::Bond);
	else return Actual360(); //note default bad but just a POC 
}

QuantLib::Compounding Compound(std::string compounding)
{
	if(compounding == "Simple") return QuantLib::Simple;
	else if(compounding == "Compounded") return QuantLib::Compounded;
	else if(compounding == "Continuous") return QuantLib::Continuous;
	else if(compounding == "SimpleThenCompounded") return QuantLib::SimpleThenCompounded;
	else return QuantLib::Simple; //note default bad but just a POC 
}

QuantLib::Frequency Freq(std::string freq)
{
	if(freq == "Monthly")return Monthly; 
	else if(freq == "Quarterly")return Quarterly; 
	else if(freq == "Semiannual")return Semiannual; 
	else if(freq == "Annual")return Annual; 
	else return OtherFrequency; //note default bad but just a POC 
}

QuantLib::BusinessDayConvention BizConv(std::string bizConv)
{
	if(bizConv == "Following") return Following; 
	else if(bizConv == "ModifiedFollowing")	return ModifiedFollowing;
	else if(bizConv == "ModifiedPreceding")	return ModifiedPreceding;
	else if(bizConv == "Preceding")	return Preceding;
	else if(bizConv == "Unadjusted") return Unadjusted;
	else return Unadjusted;//note default bad but just a POC 
}

QuantLib::Calendar Holidays(std::string holidays)
{
	if(holidays == "USD:Govt") 	return UnitedStates(UnitedStates::GovernmentBond);
	else if(holidays == "USD:NYSE") return UnitedStates(UnitedStates::NYSE);
	else if(holidays == "") return NullCalendar();
	else return TARGET();//note default bad but just a POC 
}

std::string ql::SwigTest(std::string val)
{
	return val;
}

std::string ql::Index(std::string marketName, std::string curveName, std::string indexName, std::string indexType, std::string tenor, std::string fixings)
{
	try
	{
		boost::shared_ptr<IborIndex> index;

		if(relinkableYts[marketName].count(curveName) < 1 )
		{
			 RelinkableHandle<YieldTermStructure> curve;
		     relinkableYts[marketName][curveName] =  curve;
		}

		RelinkableHandle<YieldTermStructure> c = relinkableYts[marketName][curveName];
		
		if(indexType == "Euribor") 
		{
			if(tenor == "1M" || tenor == "1m") index = (boost::shared_ptr<IborIndex>)(new Euribor1M(c));
			else if(tenor == "3M" || tenor == "3m") index = (boost::shared_ptr<IborIndex>)(new Euribor3M(c));
			else if(tenor == "6M" || tenor == "6m") index = (boost::shared_ptr<IborIndex>)(new Euribor6M(c));
			else if(tenor == "1Y" || tenor == "1y") index = (boost::shared_ptr<IborIndex>)(new Euribor1Y(c));
			else return "#index unknown";
		}
		else if(indexType == "USDLibor") index = (boost::shared_ptr<IborIndex>)(new USDLibor(getPeriod(tenor), c));
		else return "#index unknown";
	
		if(fixings != "") 
		{
			std::vector<std::vector<std::string>> fixingVector = stringTo2DVector(fixings);
			for each(std::vector<std::string> f in fixingVector)
				index->addFixing(Date(stoi(f[0])), stod(f[1]));
			//index->addFixing(Date(17, July, 2008),0.0278625);
		}
		indexs[marketName][indexName] = index;
		return indexName;
	}
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error" ;
	}
}

//date
int ql::NextImmDate(int date)
{
	return IMM::nextDate(Date(date)).serialNumber();
}

int ql::NextBizDate(int date, std::string period, std::string bizDayConv, bool endOfMonth, std::string holidays)
{
	try 
	{
		Date d(date);
		
		Calendar calendar = Holidays(holidays);
	    return calendar.advance(d, getPeriod(period), BizConv(bizDayConv), endOfMonth).serialNumber();
		//return calendar.adjust(d).serialNumber();
	}
	catch (...) 
	{ 
		return 0;
	}
}

int ql::NextBizDate(int date, std::string holidays)
{
	try 
	{
		Date d(date);
		
		Calendar calendar = Holidays(holidays);
		return calendar.adjust(d).serialNumber();
	}
	catch (...) 
	{ 
		return 0;
	}
}

//engines could be exposed and called seperatly
std::string SwapEngine(std::string marketName, std::string curveName, std::string discountCurveName)
{
	try
	{
		boost::shared_ptr<YieldTermStructure> discCurve = rateCurves[marketName][discountCurveName];
		if(!discCurve) 	return "#discount curve missing:" + discountCurveName;
		
		boost::shared_ptr<YieldTermStructure> forcCurve = rateCurves[marketName][curveName];
		if(!forcCurve) return "#forcast curve missing:" + curveName;

		if(relinkableYts[marketName].count(curveName) < 1 )
		{
			 RelinkableHandle<YieldTermStructure> forecastCurve;
		     relinkableYts[marketName][curveName] =  forecastCurve;
		}

		if(relinkableYts[marketName].count(discountCurveName) < 1 )
		{
			 RelinkableHandle<YieldTermStructure> discountCurve;
			 relinkableYts[marketName][discountCurveName] =  discountCurve;
		}
		
		boost::shared_ptr<PricingEngine> swapEngine(new DiscountingSwapEngine(relinkableYts[marketName][discountCurveName]));
		pricingEngines[marketName][curveName] = swapEngine;
		relinkableYts[marketName][discountCurveName].linkTo(discCurve);
		relinkableYts[marketName][curveName].linkTo(forcCurve);

		return curveName;
	} 
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error";
	}
}

std::string BondEngine(std::string marketName, std::string curveName, std::string discountCurveName)
{
	try
	{
		boost::shared_ptr<YieldTermStructure> discCurve = rateCurves[marketName][discountCurveName];
		if(!discCurve) return "#discount curve missing:" + discountCurveName;
		
		boost::shared_ptr<YieldTermStructure> forcCurve = rateCurves[marketName][curveName];
		if(!forcCurve) return "#forcast curve missing:" + curveName;
       
		if(relinkableYts[marketName].count(curveName) < 1 )
		{
			 RelinkableHandle<YieldTermStructure> forecastCurve;
		     relinkableYts[marketName][curveName] =  forecastCurve;
		}

		if(relinkableYts[marketName].count(discountCurveName) < 1 )
		{
			 RelinkableHandle<YieldTermStructure> discountCurve;
			 relinkableYts[marketName][discountCurveName] =  discountCurve;
		}

		boost::shared_ptr<PricingEngine> bondEngine(new DiscountingBondEngine(relinkableYts[marketName][discountCurveName]));
		relinkableYts[marketName][curveName].linkTo(forcCurve);
        relinkableYts[marketName][discountCurveName].linkTo(discCurve);

    	pricingEngines[marketName][curveName] = bondEngine;

		return curveName;
	} 
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error";
	}
}

std::string DefaultEngine(std::string marketName, std::string curveName, std::string discountCurveName, double recoveryRate)
{
	try
	{
		//just getting demos runnings thats all
		boost::shared_ptr<QuantLib::PiecewiseDefaultCurve<HazardRate, BackwardFlat>>  forecastCurve = defaultCurves[marketName][curveName];
		if(!forecastCurve) return "#default curve missing:" + curveName;

		boost::shared_ptr<QuantLib::YieldTermStructure> discountCurve = rateCurves[marketName][discountCurveName];
		if(!discountCurve) return "#discount curve missing";
		
		boost::shared_ptr<PricingEngine> defaultEngine(new MidPointCdsEngine(Handle<DefaultProbabilityTermStructure>(forecastCurve), recoveryRate, Handle<YieldTermStructure>(discountCurve)));
		pricingEngines[marketName][curveName] = defaultEngine;

		return curveName;
	} 
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error";
	}
}

std::string SwaptionG2Engines(std::string marketName, std::string curveName, std::string volSurfName, double range, int intervals)
{
	try
	{
		//G2 (analytic formulae) calibration
		boost::shared_ptr<QuantLib::YieldTermStructure> curve = rateCurves[marketName][curveName];
		if(!curve) return "#unknown curve";
		std::vector<boost::shared_ptr<CalibrationHelper>> swaptions = vsurfCalibHelpers[marketName][volSurfName];

		boost::shared_ptr<G2> model(new G2(Handle<YieldTermStructure>(curve)));

		boost::shared_ptr<PricingEngine> pricingEngine(new TreeSwaptionEngine(model, 50));
		pricingEngines[marketName][volSurfName] = pricingEngine;

		boost::shared_ptr<PricingEngine> swaptionEngine(new G2SwaptionEngine(model, range, intervals));
		for each (boost::shared_ptr<CalibrationHelper> swaption in swaptions)
			swaption->setPricingEngine(swaptionEngine);
			
		LevenbergMarquardt om;
		model->calibrate(swaptions, om, EndCriteria(400, 100, 1.0e-8, 1.0e-8, 1.0e-8));

		vsurfModels[marketName][volSurfName] = model;

		//std::cout << "calibrated to:\n"
        //        << "a     = " << model->params()[0] << ", "
        //        << "sigma = " << model->params()[1] << "\n"
        //        << "b     = " << model->params()[2] << ", "
        //        << "eta   = " << model->params()[3] << "\n"
        //        << "rho   = " << model->params()[4]
        //        << std::endl << std::endl;

		return volSurfName;
	} 
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error";
	}
}

std::string SwaptionHW1Engines(std::string marketName, std::string curveName, std::string volSurfName)
{
	try
	{
		//Hull-White (analytic formulae) calibration
		boost::shared_ptr<QuantLib::YieldTermStructure> curve = rateCurves[marketName][curveName];
		if(!curve) return "#unknown curve";
		std::vector<boost::shared_ptr<CalibrationHelper>>  swaptions = vsurfCalibHelpers[marketName][volSurfName];

		boost::shared_ptr<HullWhite> model(new HullWhite(Handle<YieldTermStructure>(curve)));

		boost::shared_ptr<PricingEngine> pricingEngine(new TreeSwaptionEngine(model, 50));
		pricingEngines[marketName][volSurfName] = pricingEngine;

		for each (boost::shared_ptr<CalibrationHelper> swaption in swaptions)
			swaption->setPricingEngine(boost::shared_ptr<PricingEngine>(new JamshidianSwaptionEngine(model)));
		
		LevenbergMarquardt om;
		model->calibrate(swaptions, om, EndCriteria(400, 100, 1.0e-8, 1.0e-8, 1.0e-8));

		vsurfModels[marketName][volSurfName] = model;

		return volSurfName;
	} 
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error";
	}
}

std::string SwaptionHW2Engines(std::string marketName, std::string curveName, std::string volSurfName, int step)
{
	try
	{
		//Hull-White (numerical) calibration
		boost::shared_ptr<QuantLib::YieldTermStructure> curve = rateCurves[marketName][curveName];
		if(!curve) return "#unknown curve";
		std::vector<boost::shared_ptr<CalibrationHelper>> swaptions = vsurfCalibHelpers[marketName][volSurfName];

		boost::shared_ptr<HullWhite> model(new HullWhite(Handle<YieldTermStructure>(curve)));
		
		boost::shared_ptr<PricingEngine> pricingEngine(new TreeSwaptionEngine(model, 50));
		pricingEngines[marketName][volSurfName] = pricingEngine;

		std::list<QuantLib::Time> times;

		for each (boost::shared_ptr<CalibrationHelper> swaption in swaptions)
			swaption->addTimesTo(times); 

		QuantLib::TimeGrid grid(times.begin(), times.end(), step);

		for each (boost::shared_ptr<CalibrationHelper> swaption in swaptions)
			swaption->setPricingEngine(boost::shared_ptr<PricingEngine>(new TreeSwaptionEngine(model, grid)));
		
		LevenbergMarquardt om;
		model->calibrate(swaptions, om, EndCriteria(400, 100, 1.0e-8, 1.0e-8, 1.0e-8));

		vsurfModels[marketName][volSurfName] = model;

		return volSurfName;
	} 
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error";
	}
}

std::string SwaptionBKEngines(std::string marketName, std::string curveName, std::string volSurfName, int step)
{
	try
	{
		//Black-Karasinski (numerical) calibration
		boost::shared_ptr<QuantLib::YieldTermStructure> curve = rateCurves[marketName][curveName];
		if(!curve) return "#unknown curve";
		std::vector<boost::shared_ptr<CalibrationHelper>> swaptions = vsurfCalibHelpers[marketName][volSurfName];
		
		boost::shared_ptr<BlackKarasinski> model(new BlackKarasinski(Handle<YieldTermStructure>(curve)));

		boost::shared_ptr<PricingEngine> pricingEngine(new TreeSwaptionEngine(model, 50));
		pricingEngines[marketName][volSurfName] = pricingEngine;

		std::list<QuantLib::Time> times;
		for each (boost::shared_ptr<CalibrationHelper> swaption in swaptions)
			swaption->addTimesTo(times); 

		QuantLib::TimeGrid grid(times.begin(), times.end(), step);

		for each (boost::shared_ptr<CalibrationHelper> swaption in swaptions)
			swaption->setPricingEngine(boost::shared_ptr<PricingEngine>(new TreeSwaptionEngine(model, grid)));

		LevenbergMarquardt om;
		model->calibrate(swaptions, om, EndCriteria(400, 100, 1.0e-8, 1.0e-8, 1.0e-8));

		vsurfModels[marketName][volSurfName] = model;

		return volSurfName;
	} 
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error";
	}
}

//pricing structures
std::string ql::YieldCurve(std::string marketName, std::string curveName, std::string discountCurveName, int settlementDate, std::string rates, std::string dayCount, double tolerance, std::string holidays)
{
	try 
	{
	    std::vector<std::string> ratesVector = stringToVector(rates);
		Calendar calendar = Holidays(holidays);
		Date settleDate(settlementDate);
        settleDate = calendar.adjust(settleDate);
		if(tolerance == 0)	tolerance = 1.0e-15;
		
		std::vector<boost::shared_ptr<RateHelper>> instruments;

		for each(std::string r in ratesVector)
		{
			boost::shared_ptr<RateHelper> rate = rateHelpers[marketName][r];
			if(rate) instruments.push_back(rate);
		}

		rateCurves[marketName][curveName] = boost::shared_ptr<YieldTermStructure>(new PiecewiseYieldCurve<Discount,LogLinear>(settleDate, instruments, DayCount(dayCount), tolerance));
		
		SwapEngine(marketName, curveName, discountCurveName == "" ? curveName : discountCurveName);

		return curveName; 

	}
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error" ;
	}
}

std::string ql::FlatForwardCurve(std::string marketName, std::string curveName, std::string discountCurveName, int settlementDate, double rate, std::string dayCount)
{
	try
	{
		Date settleDate(settlementDate);
		boost::shared_ptr<Quote> flatRate(new SimpleQuote(rate));
		boost::shared_ptr<FlatForward> curve = boost::shared_ptr<FlatForward>(new FlatForward(settleDate, Handle<Quote>(flatRate), DayCount(dayCount)));
		rateCurves[marketName][curveName] = curve;

		SwapEngine(marketName, curveName, discountCurveName == "" ? curveName : discountCurveName);

		return curveName; 
	}
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error" ;
	}
}

std::string ql::FlatForwardCurve(std::string marketName, std::string curveName, std::string discountCurveName, int settlementDate, double rate, std::string dayCount, std::string cpnFrq, std::string compounded)
{
	try
	{
		Date settleDate(settlementDate);
		boost::shared_ptr<Quote> flatRate(new SimpleQuote(rate));
		boost::shared_ptr<FlatForward> curve = boost::shared_ptr<FlatForward>(new FlatForward(settleDate, Handle<Quote>(flatRate), DayCount(dayCount), Compound(compounded), Freq(cpnFrq)));

		rateCurves[marketName][curveName] = curve;

		SwapEngine(marketName, curveName, discountCurveName == "" ? curveName : discountCurveName);

		return curveName; 
	}
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error" ;
	}
}

std::string ql::BondCurve(std::string marketName, std::string curveName, std::string discountCurveName, int settlementDate, std::string rates, std::string dayCount, double tolerance, std::string holidays)
{
	try 
	{
	    std::vector<std::string> ratesVector = stringToVector(rates);
		Calendar calendar = Holidays(holidays);
		Date settleDate(settlementDate);
        settleDate = calendar.adjust(settleDate);
		if(tolerance == 0)	tolerance = 1.0e-15;

		std::vector<boost::shared_ptr<RateHelper>> instruments;

		for each(std::string r in ratesVector)
		{
			boost::shared_ptr<RateHelper> rate = rateHelpers[marketName][r];
			if(rate) instruments.push_back(rate);
		}

		rateCurves[marketName][curveName] = boost::shared_ptr<YieldTermStructure>(new PiecewiseYieldCurve<Discount,LogLinear>(settleDate, instruments, DayCount(dayCount), tolerance));
		
		BondEngine(marketName, curveName, discountCurveName);

		return curveName; 

	}
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error" ;
	}
}

std::string ql::DefaultCurve(std::string marketName, std::string curveName, std::string discountCurveName, int settlementDate, std::string spreads, double recoveryRate, std::string dayCount, std::string holidays)
{
	try 
	{
		std::vector<std::string> spreadsVector = stringToVector(spreads);
		Calendar calendar = Holidays(holidays);
		Date settleDate(settlementDate);
        settleDate = calendar.adjust(settleDate);
		std::vector<boost::shared_ptr<DefaultProbabilityHelper> > instruments;
		
		for each(std::string s in spreadsVector)
		{
			boost::shared_ptr<DefaultProbabilityHelper> spread = defaultHelpers[marketName][s];
			if(spread) instruments.push_back(spread);
		}

        defaultCurves[marketName][curveName] = boost::shared_ptr<PiecewiseDefaultCurve<HazardRate, BackwardFlat>>(new PiecewiseDefaultCurve<HazardRate, BackwardFlat>(settleDate, instruments, DayCount(dayCount)));

		DefaultEngine(marketName, curveName, discountCurveName, recoveryRate);

		return curveName;

	} 
	catch (std::exception& e) 
	{
		return e.what();
	}
	catch (...) 
	{ 
		return "#unknown error" ;
	}
}

std::string ql::VolSurf(std::string marketName, std::string curveName, std::string volSurfName, std::string vols, std::string index, std::string model)
{
	try 
	{	
		boost::shared_ptr<IborIndex> indx = indexs[marketName][index];
		if(!indx) return "#unknown index";
		
		boost::shared_ptr<QuantLib::YieldTermStructure> curve = rateCurves[marketName][curveName];
		if(!curve) return "#unknown curve";
		
		std::vector<std::vector<std::string>> v1 = stringTo2DVector(vols);
		std::vector<boost::shared_ptr<CalibrationHelper>> calibHelpers;

		int i = 0;
		std::string periodLabel;
		QuantLib::Period maturity;
		for each(std::vector<std::string> v2 in v1)
		{
			if(i > 0)
			{
				int j = 0;
				maturity = getPeriod(v1[0][i]);
				vsurfPeriodLabels[marketName][volSurfName].push_back(maturity);

				QuantLib::Period period;
				for each(std::string v in v2)
				{
					if(j > 0 && stod(v) > 0)
					{
						period = getPeriod(v1[j][0]);
						if(i == 1)	
							vsurfMaturityLabels[marketName][volSurfName].push_back(period); 
						calibHelpers.push_back(boost::shared_ptr<CalibrationHelper>(new SwaptionHelper(maturity, period, setQuote(marketName, "", stod(v)), indx, indx->tenor(), indx->dayCounter(), indx->dayCounter(), Handle<QuantLib::YieldTermStructure>(curve))));
						vsurfMarketVols[marketName][volSurfName].push_back(stod(v));
					}
					j++;
				}
			}
			i++;
		}

		vsurfCalibHelpers[marketName][volSurfName] = calibHelpers;
		std::vector<std::string> modelVector = stringToVector(model);
		
		std::string engineName;
		
		//sabre??????????
		if(modelVector[0] == "G2") engineName = SwaptionG2Engines(marketName, curveName, volSurfName, stod(modelVector[1]), stoi(modelVector[2]));
		else if(modelVector[0] == "HW1") engineName = SwaptionHW1Engines(marketName, curveName, volSurfName);
		else if(modelVector[0] == "HW2") engineName = SwaptionHW2Engines(marketName, curveName, volSurfName, stoi(modelVector[1]));
		else if(modelVector[0] == "BK") engineName = SwaptionBKEngines(marketName, curveName, volSurfName, stoi(modelVector[1]));

	}
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error" ;
	}

	return  volSurfName;
}

//rate helpers
std::string ql::DepoRate(std::string marketName, std::string instName, double rate, std::string tenor,  int fixingDays, std::string dayCount, std::string bizConv,  std::string holidays)
{
	try 
	{	
		boost::shared_ptr<RateHelper> depo(new DepositRateHelper(setQuote(marketName, instName, rate), getPeriod(tenor), fixingDays, Holidays(holidays), BizConv(bizConv), true, DayCount(dayCount)));
		rateHelpers[marketName][instName] = depo;
		return  instName;
	}
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error" ;
	}
}

std::string ql::FraRate(std::string marketName, std::string instName, double rate, int start, int end,  int fixingDays, std::string dayCount, std::string bizConv, std::string holidays)
{
	try 
	{
		boost::shared_ptr<RateHelper> fra(new FraRateHelper(setQuote(marketName, instName, rate), start, end, fixingDays, Holidays(holidays), BizConv(bizConv), true,  DayCount(dayCount)));
		rateHelpers[marketName][instName] =  fra;
		return  instName;
	}
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error" ;
	}
}

std::string ql::FutRate(std::string marketName, std::string instName, double rate, int startDate, int futMonths,  std::string dayCount, std::string bizConv, std::string holidays)
{
	try 
	{
		boost::shared_ptr<RateHelper> fut(new FuturesRateHelper(setQuote(marketName, instName, rate), Date(startDate), futMonths, Holidays(holidays), BizConv(bizConv), true, DayCount(dayCount)));
		rateHelpers[marketName][instName] = fut;
		return  instName;
	}
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error" ;
	}
}

std::string ql::SwapRate(std::string marketName, std::string instName, double rate, std::string tenor, int fixingDays, int forwardStart, std::string floatLegIndex, std::string fixedLegFreq, std::string fixedLegDayCount, std::string fixedLegBizConv, std::string holidays)
{
	try 
	{
		boost::shared_ptr<IborIndex> index = indexs[marketName][floatLegIndex];
		if(!index) return "#unknown index";

		boost::shared_ptr<RateHelper> swap(new SwapRateHelper(setQuote(marketName, instName, rate), getPeriod(tenor), Holidays(holidays), Freq(fixedLegFreq), BizConv(fixedLegBizConv), DayCount(fixedLegDayCount), index, Handle<Quote>(), forwardStart*Days));
		rateHelpers[marketName][instName] = swap;
		return  instName;
	}
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error" ;
	}
}

std::string ql::CdsSpread(std::string marketName, std::string instName, double spread, double recoveryRate, std::string tenor, int fixingDays, std::string discountCurveName, std::string freq,  std::string dayCount, std::string bizConv, std::string holidays)
{
	try 
	{
		boost::shared_ptr<QuantLib::YieldTermStructure> discountCurve = rateCurves[marketName][discountCurveName];
		if(!discountCurve) return "#cant find discount curve";
		boost::shared_ptr<DefaultProbabilityHelper> cds(new SpreadCdsHelper(setQuote(marketName, instName, spread), getPeriod(tenor), fixingDays, Holidays(holidays), Freq(freq), BizConv(bizConv), DateGeneration::TwentiethIMM, DayCount(dayCount), recoveryRate, Handle<QuantLib::YieldTermStructure>(discountCurve)));	
		defaultHelpers[marketName][instName] = cds;
		return  instName;
	}
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error" ;
	}
}

//trades can also be used for pricing
//rate 
std::string ql::VanillaSwap(std::string marketName, std::string cacheName, std::string id, std::string curveName, double nominal, int start, int maturity, double fixedRate, std::string payRec, std::string index, double spread, std::string  fixLegFrq, std::string fltLegFrq, std::string fixLegConv,  std::string fltLegConv, std::string fixLegDayCount, std::string fltLegDayCount, std::string holidays)
{
	try 
	{ 
		boost::shared_ptr<IborIndex> indx = indexs[marketName][index];
		if(!indx) return "#unknown index";

		Date startDate(start);
		Date maturityDate(maturity);
		VanillaSwap::Type type =  payRec == "Receiver" ? VanillaSwap::Receiver : VanillaSwap::Payer;
		Calendar calendar = Holidays(holidays);
		
		Schedule fixedSchedule(startDate, maturityDate, QuantLib::Period(Freq(fixLegFrq)), calendar, BizConv(fixLegConv), BizConv(fixLegConv), DateGeneration::Forward, false);
		Schedule floatSchedule(startDate, maturityDate, QuantLib::Period(Freq(fltLegFrq)), calendar, BizConv(fltLegConv), BizConv(fltLegConv), DateGeneration::Forward, false);
		
		caches[cacheName][id] = boost::shared_ptr<QuantLib::VanillaSwap>(new QuantLib::VanillaSwap(type, nominal, fixedSchedule, fixedRate, DayCount(fixLegDayCount), floatSchedule, indx, spread, DayCount(fltLegDayCount)));
		
		tradeEngineMap[cacheName][id] = curveName;

		return id;
	} 
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error";
	}
}

std::string ql::BasisSwap(std::string marketName, std::string cacheName, std::string id, double nominal, int start, int maturity, std::string payRec, std::string curveName1, std::string index1, double spread1,  std::string fltLegFrq1, std::string fltLegConv1, std::string fltLegDayCount1,	std::string curveName2, std::string index2, double spread2,  std::string fltLegFrq2, std::string fltLegConv2, std::string fltLegDayCount2, std::string holidays)
{
	try 
	{ 
		boost::shared_ptr<IborIndex> indx1 = indexs[marketName][index1];
		if(!indx1) return "#unknown index1";

		boost::shared_ptr<IborIndex> indx2 = indexs[marketName][index2];
		if(!indx2) return "#unknown index2";

		Date startDate(start);
		Date maturityDate(maturity);
		BasisSwap::Type type =  payRec == "Receiver" ? BasisSwap::Receiver : BasisSwap::Payer;
		Calendar calendar = Holidays(holidays);

		Schedule floatSchedule1(startDate, maturityDate, QuantLib::Period(Freq(fltLegFrq1)), calendar, BizConv(fltLegConv1), BizConv(fltLegConv1), DateGeneration::Forward, false);
		Schedule floatSchedule2(startDate, maturityDate, QuantLib::Period(Freq(fltLegFrq2)), calendar, BizConv(fltLegConv2), BizConv(fltLegConv2), DateGeneration::Forward, false);
		
		caches[cacheName][id] = boost::shared_ptr<QuantLib::BasisSwap>(new 
			QuantLib::BasisSwap(type, nominal, floatSchedule1, indx1,  spread1, DayCount(fltLegDayCount1), 
									 floatSchedule2, indx2,  spread2, DayCount(fltLegDayCount2))); 
		
		tradeEngineMap[cacheName][id] = curveName1; //xccy? need differnet engine or split legs

		return id;
	} 
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error";
	}
}

std::string ql::FloatingLeg(std::string marketName, std::string cacheName, std::string id, double nominal, int start, int maturity, std::string payRec, std::string curveName, std::string index, double spread,  std::string fltLegFrq, std::string fltLegConv, std::string fltLegDayCount, std::string holidays)
{
	try 
	{ 
		boost::shared_ptr<IborIndex> indx = indexs[marketName][index];
		if(!indx) return "#unknown index";

		Date startDate(start);
		Date maturityDate(maturity);
		SingleFloatingLeg::Type type =  payRec == "Receiver" ? SingleFloatingLeg::Receiver : SingleFloatingLeg::Payer;
		Calendar calendar = Holidays(holidays);

		Schedule floatSchedule(startDate, maturityDate, QuantLib::Period(Freq(fltLegFrq)), calendar, BizConv(fltLegConv), BizConv(fltLegConv), DateGeneration::Forward, false);
			
		caches[cacheName][id] = boost::shared_ptr<QuantLib::SingleFloatingLeg>(new QuantLib::SingleFloatingLeg(type, nominal, floatSchedule, indx,  spread, DayCount(fltLegDayCount))); 
		
		tradeEngineMap[cacheName][id] = curveName;

		return id;
	} 
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...)
	{ 
		return "#unknown error";
	}
}

std::string ql::FixedLeg(std::string marketName, std::string cacheName, std::string id, std::string curveName, double nominal, int start, int maturity, double fixedRate, std::string payRec, std::string index, std::string  fixLegFrq, std::string fixLegConv,  std::string fixLegDayCount, std::string holidays)
{
	try 
	{ 
		Date startDate(start);
		Date maturityDate(maturity);
		SingleFixedLeg::Type type =  payRec == "Receiver" ? SingleFixedLeg::Receiver : SingleFixedLeg::Payer;
		Calendar calendar = Holidays(holidays);
		
		Schedule fixedSchedule(startDate, maturityDate, QuantLib::Period(Freq(fixLegFrq)), calendar, BizConv(fixLegConv), BizConv(fixLegConv), DateGeneration::Forward, false);
				
		caches[cacheName][id] = boost::shared_ptr<QuantLib::SingleFixedLeg>(new QuantLib::SingleFixedLeg(type, nominal, fixedSchedule, fixedRate, DayCount(fixLegDayCount)));
		
		tradeEngineMap[cacheName][id] = curveName;

		return id;
	} 
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error";
	}
}

//rate options
std::string ql::Swaption(std::string marketName, std::string cacheName, std::string id, std::string curveName, std::string volSurfName, double nominal, int start, int maturity, double strike, std::string payRec, std::string index, double spread, std::string  fixLegFrq, std::string fltLegFrq, std::string fixLegConv,  std::string fltLegConv, std::string fixLegDayCount, std::string fltLegDayCount, std::string holidays)
{
	try 
	{ 
		boost::shared_ptr<IborIndex> indx = indexs[marketName][index];
		if(!indx) return "#unknown index";

		Date startDate(start);
		Date maturityDate(maturity);
		VanillaSwap::Type type =  payRec == "Receiver" ? VanillaSwap::Receiver : VanillaSwap::Payer;
		Calendar calendar = Holidays(holidays);
		
		Schedule fixedSchedule(startDate, maturityDate, QuantLib::Period(Freq(fixLegFrq)), calendar, BizConv(fixLegConv), BizConv(fixLegConv), DateGeneration::Forward, false);
		Schedule floatSchedule(startDate, maturityDate, QuantLib::Period(Freq(fltLegFrq)), calendar, BizConv(fltLegConv), BizConv(fltLegConv), DateGeneration::Forward, false);
		
		boost::shared_ptr<QuantLib::VanillaSwap> swap = boost::shared_ptr<QuantLib::VanillaSwap>(new QuantLib::VanillaSwap(type, nominal, fixedSchedule, strike, DayCount(fixLegDayCount), floatSchedule, indx, spread, DayCount(fltLegDayCount)));
		
		Size i;
		std::vector<Date> bermudanDates;
        const std::vector<boost::shared_ptr<CashFlow>>& leg = swap->fixedLeg();
        for (i=0; i<leg.size(); i++) 
		{
            boost::shared_ptr<Coupon> coupon = boost::dynamic_pointer_cast<Coupon>(leg[i]);
            bermudanDates.push_back(coupon->accrualStartDate());
        }

		boost::shared_ptr<Exercise> europeanExercise(new EuropeanExercise(startDate));

        caches[cacheName][id] = boost::shared_ptr<QuantLib::Swaption>(new QuantLib::Swaption(swap, europeanExercise));

		tradeEngineMap[cacheName][id] = volSurfName;

		return id;
	} 
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error";
	}
}

std::string ql::BermudanSwaption(std::string marketName, std::string cacheName, std::string id, std::string curveName, std::string volSurfName, double nominal, int start, int maturity, double strike, std::string payRec, std::string index, double spread, std::string  fixLegFrq, std::string fltLegFrq, std::string fixLegConv,  std::string fltLegConv, std::string fixLegDayCount, std::string fltLegDayCount, std::string holidays)
{
	try 
	{ 
		boost::shared_ptr<IborIndex> indx = indexs[marketName][index];
		if(!indx) return "#unknown index";

		Date startDate(start);
		Date maturityDate(maturity);
		VanillaSwap::Type type =  payRec == "Receiver" ? VanillaSwap::Receiver : VanillaSwap::Payer;
		Calendar calendar = Holidays(holidays);
		
		Schedule fixedSchedule(startDate, maturityDate, QuantLib::Period(Freq(fixLegFrq)), calendar, BizConv(fixLegConv), BizConv(fixLegConv), DateGeneration::Forward, false);
		Schedule floatSchedule(startDate, maturityDate, QuantLib::Period(Freq(fltLegFrq)), calendar, BizConv(fltLegConv), BizConv(fltLegConv), DateGeneration::Forward, false);
		
		boost::shared_ptr<QuantLib::VanillaSwap> swap = boost::shared_ptr<QuantLib::VanillaSwap>(new QuantLib::VanillaSwap(type, nominal, fixedSchedule, strike, DayCount(fixLegDayCount), floatSchedule, indx, spread, DayCount(fltLegDayCount)));
		
		Size i;
		std::vector<Date> bermudanDates;
        const std::vector<boost::shared_ptr<CashFlow>>& leg = swap->fixedLeg();
        for (i=0; i<leg.size(); i++) 
		{
            boost::shared_ptr<Coupon> coupon = boost::dynamic_pointer_cast<Coupon>(leg[i]);
            bermudanDates.push_back(coupon->accrualStartDate());
        }

		boost::shared_ptr<Exercise> bermudanExercise(new BermudanExercise(bermudanDates));

        caches[cacheName][id] = boost::shared_ptr<QuantLib::Swaption>(new QuantLib::Swaption(swap, bermudanExercise));

		tradeEngineMap[cacheName][id] = volSurfName;

		return id;
	} 
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error";
	}	
}

//credit
std::string ql::CreditDefaultSwap(std::string marketName, std::string cacheName, std::string id, std::string curveName, double quotedSpread, std::string protSellBuy, double nominal, int start, int maturity, std::string premFreq, std::string premConv, std::string payConv, std::string dayCount, std::string holidays)
{
	try
	{
		//just getting demos runnings thats all
		Protection::Side type =  protSellBuy == "Buy" ? Protection::Buyer : Protection::Seller;
		Date startDate(start);
		Date maturityDate(maturity);

		Schedule cdsSchedule = MakeSchedule().from(startDate).to(maturityDate).withFrequency(Freq(premFreq)).withCalendar(Holidays(holidays)).withTerminationDateConvention(BizConv(premConv)).withRule(DateGeneration::TwentiethIMM);
        
		caches[cacheName][id] = boost::shared_ptr<QuantLib::CreditDefaultSwap>(new QuantLib::CreditDefaultSwap(type, nominal, quotedSpread, cdsSchedule, BizConv(payConv), DayCount(dayCount)));

		tradeEngineMap[cacheName][id] = curveName;

		return id;
	} 
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error";
	}
}

std::string ql::ForwardRateAgreement(std::string marketName, std::string cacheName, std::string id, std::string curveName, double nominal, int start, int maturity, double fixedRate, std::string payRec, std::string index)
{
	try 
	{ 
		boost::shared_ptr<IborIndex> indx = indexs[marketName][index];
		if(!indx) return "#unknown index2";

		//note swap&bond traders refer to long as long paper short cash, depo guys looking at cash funding refer to long as long cash
		//also start is actually the settle date, maturity is period end date, using start and maturity to help out with query tool
		Date startDate(start);
        Date maturityDate(maturity);
		Position::Type type =  payRec == "Receiver" ? Position::Long : Position::Short;

		caches[cacheName][id] = boost::shared_ptr<QuantLib::ForwardRateAgreement>(new QuantLib::ForwardRateAgreement(startDate, maturityDate, type, fixedRate,  nominal, indx, relinkableYts[marketName][curveName]));
		
		tradeEngineMap[cacheName][id] =  curveName;


		return id;
	} 
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error";
	}
}

//bond
std::string ql::FixedRateBondBuild(std::string marketName, std::string bondName, double coupon, double cleanPrice, std::string couponFrq, double redemption, int settlementDays, int effectiveDate, int terminationDate, std::string dayCount, std::string payConv, std::string termConv, std::string bondConv, std::string holidays)
{
	try 
	{ 
		Date effDate =  Date(effectiveDate);
		Date termDate = Date(terminationDate);
		DayCounter dc = DayCount(dayCount);

		//not a trade stored for reuse to build FixedRateBondTrade and price
        Schedule fixedBondSchedule(effDate, termDate, QuantLib::Period(Freq(couponFrq)), Holidays(holidays), BizConv(payConv), BizConv(termConv), DateGeneration::Backward, false);
		boost::shared_ptr<QuantLib::FixedRateBond> bond(new QuantLib::FixedRateBond(Natural(settlementDays), 100, fixedBondSchedule, std::vector<Rate>(1, coupon),  dc, BizConv(bondConv), redemption, effDate));
	
		//used for bond curves
		boost::shared_ptr<FixedRateBondHelper> helper(new FixedRateBondHelper(setQuote(marketName, bondName, cleanPrice), settlementDays, 100.0, fixedBondSchedule, std::vector<Rate>(1,coupon), dc, BizConv(bondConv), redemption, effDate));
		rateHelpers[marketName][bondName] = helper;

		bonds[marketName][bondName] = boost::shared_ptr<QuantLib::FixedRateBond>(bond);

		return  bondName;
	} 
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error";
	}
}

std::string ql::FixedRateBond(std::string marketName, std::string cacheName, std::string id, std::string bondName, std::string curveName, double nominal,  int settlementDate, double tradePrice)
{
	try 
	{ 
		boost::shared_ptr<Bond> bnd = bonds[marketName][bondName];
		if(!bnd) return "#unknown bond";

		QuantLib::FixedRateBond bond = *dynamic_cast<QuantLib::FixedRateBond*> (bnd.get());
		caches[cacheName][id] = boost::shared_ptr<FixedRateBondWrap>(new FixedRateBondWrap(bond, nominal/100, settlementDate, tradePrice));

		tradeEngineMap[cacheName][id] =  curveName;

		return id;
	} 
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{
		return "#unknown error";
	}
}

std::string ql::FloatingRateBondBuild(std::string marketName, std::string bondName, double spread, std::string curveName, std::string index, std::string couponFrq, double redemption, int settlementDays, int effectiveDate, int terminationDate, std::string dayCount, std::string payConv, std::string termConv, std::string bondConv, std::string holidays)
{
	try 
	{ 
		boost::shared_ptr<IborIndex> indx = indexs[marketName][index];
		if(!indx) return "#unknown index";
		
		setQuote(marketName, bondName, spread);

		//not a trade stored for reuse to build FloatingRateBondTrade and price
		Schedule floatingBondSchedule(Date(effectiveDate), Date(terminationDate), Period(Freq(couponFrq)), Holidays(holidays), BizConv(payConv), BizConv(termConv), DateGeneration::Backward, true);

		QuantLib::FloatingRateBond* bond =  new QuantLib::FloatingRateBond(settlementDays, 100, floatingBondSchedule, indx,  DayCount(dayCount),  BizConv(bondConv), 2, std::vector<Real>(1, 1.0), std::vector<Rate>(1, spread), std::vector<Rate>(), std::vector<Rate>(), true, redemption, Date(effectiveDate));

		bonds[marketName][bondName] = boost::shared_ptr<QuantLib::Bond>(bond);
     
		// optionLet volatilities
		Volatility volatility = 0.0;
        Handle<OptionletVolatilityStructure> vol = Handle<OptionletVolatilityStructure>(boost::shared_ptr<OptionletVolatilityStructure>(new ConstantOptionletVolatility(settlementDays, Holidays(holidays), ModifiedFollowing, volatility, Actual365Fixed())));

		// Coupon pricers
		boost::shared_ptr<IborCouponPricer> pricer(new BlackIborCouponPricer);
        pricer->setCapletVolatility(vol);
        setCouponPricer(bond->cashflows(), pricer);
		         
		return bondName;
	} 
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error";
	}
}

std::string ql::FloatingRateBond(std::string marketName, std::string cacheName, std::string id, std::string bondName, std::string curveName, double nominal,  int settlementDate, double tradePrice)
{
	try 
	{ 
		boost::shared_ptr<Bond> bnd = bonds[marketName][bondName];
		if(!bnd) return "#unknown bond";

		QuantLib::FloatingRateBond bond = *dynamic_cast<QuantLib::FloatingRateBond*> (bnd.get());
		caches[cacheName][id] = boost::shared_ptr<FloatingRateBondWrap>(new FloatingRateBondWrap(bond, nominal/100, settlementDate, tradePrice));

		tradeEngineMap[cacheName][id] =  curveName;

		return id;
	} 
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error";
	}
}

std::string ql::ZeroCouponBondBuild(std::string marketName, std::string bondName, double redemption, int settlementDays, int effectiveDate, int terminationDate, std::string bondConv, std::string holidays)
{
	try 
	{ 
		//not a trade stored for reuse to build FloatingRateBondTrade and price
        bonds[marketName][bondName] =  boost::shared_ptr<QuantLib::Bond>(new QuantLib::ZeroCouponBond(settlementDays, Holidays(holidays), 100, Date(terminationDate), BizConv(bondConv), redemption, Date(effectiveDate)));
		         
		return bondName;
	
	} 
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error";
	}
}

std::string ql::ZeroCouponBond(std::string marketName, std::string cacheName, std::string id, std::string bondName, std::string curveName, double nominal,  int settlementDate, double tradePrice)
{
	try 
	{ 
		boost::shared_ptr<Bond> bnd = bonds[marketName][bondName];
		if(!bnd) return "#unknown bond";

		QuantLib::ZeroCouponBond bond = *dynamic_cast<QuantLib::ZeroCouponBond*> (bnd.get());
		caches[cacheName][id] = boost::shared_ptr<ZeroCouponBondWrap>(new ZeroCouponBondWrap(bond, nominal/100, settlementDate, tradePrice));

		tradeEngineMap[cacheName][id] =  curveName;

		return id;
	} 
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error";
	}
}

//fwd bond
std::string ql::FixedRateBondForward(std::string marketName, std::string fwdBondName,  std::string bondName, std::string repoCurveName, std::string bondCurveName, double price, int settlementDate, int deliveryDate, int settlementDays, std::string repoConv, std::string bondConv, std::string holidays)
{
	try
	{
		Date settleDate(settlementDate);
		Date delDate(deliveryDate);

		Handle<YieldTermStructure> bondCurve = Handle<YieldTermStructure>(rateCurves[marketName][bondCurveName]);
		Handle<YieldTermStructure> repoCurve = Handle<YieldTermStructure>(rateCurves[marketName][repoCurveName]);
				
		boost::shared_ptr<QuantLib::FixedRateBond> bond = boost::static_pointer_cast<QuantLib::FixedRateBond>(bonds[marketName][bondName]);  
		bond->setPricingEngine(boost::shared_ptr<PricingEngine>(new DiscountingBondEngine(bondCurve)));

		fwdBonds[marketName][fwdBondName] = boost::shared_ptr<QuantLib::Forward>(new QuantLib::FixedRateBondForward(settleDate, delDate, Position::Long, price, settlementDays, DayCount(repoConv), Holidays(holidays), BizConv(bondConv), bond, repoCurve, repoCurve));
			 
		return fwdBondName;
	}  
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error";
	}
}

//repo
std::string ql::Repo(std::string marketName, std::string cacheName, std::string id, std::string bondName, std::string repoCurveName, std::string bondCurveName, double strike, double nominal, int settlementDate, int deliveryDate,  int settlementDays, std::string repoConv, std::string bondConv, std::string holidays)
{
	try
	{
		ql::FixedRateBondForward(marketName, id,  bondName, repoCurveName, bondCurveName, strike, settlementDate, deliveryDate, settlementDays, repoConv, bondConv, holidays);

		boost::shared_ptr<QuantLib::Forward> fwdBnd = fwdBonds[marketName][id];
		if(!fwdBnd) return "#unknown fwdbond";
		QuantLib::FixedRateBondForward fwdBond = *dynamic_cast<QuantLib::FixedRateBondForward*> (fwdBnd.get());

		boost::shared_ptr<QuantLib::Bond> bnd = bonds[marketName][bondName];
		if(!bnd) return "#unknown bond";
		QuantLib::FixedRateBond bond = *dynamic_cast<QuantLib::FixedRateBond*> (bnd.get());

		caches[cacheName][id] = boost::shared_ptr<FixedRateBondForwardWrap>(new FixedRateBondForwardWrap(fwdBond, bond, settlementDate, deliveryDate, nominal/100, strike));

		tradeEngineMap[cacheName][id] =  repoCurveName;

		return id;
	}  
	catch (std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error";
	}
}

//market and revals
std::string ql::MarketSet(std::string marketName, int todaysDate)
{
	Settings::instance().evaluationDate() = Date(todaysDate);
	return  marketName;
}

std::string ql::MarketValueTrade(std::string marketName, std::string cacheName, std::string tradeId, std::string controlString)
{
	try
	{	
		std::stringstream res;
		std::vector<std::string> controlStrings = stringToVector(controlString);

		if(caches.count(cacheName) < 1 )
			return "tradeId,Error;" + tradeId + ",Unknown cache '" + cacheName + "'";

		if(caches[cacheName].count(tradeId) < 1 )
			return "tradeId,Error;" + tradeId + ",Unknown trade '" + tradeId + "'";

		boost::shared_ptr<Instrument> trd = caches[cacheName][tradeId];
		Instrument* trade = trd.get();

		if(pricingEngines.count(marketName) < 1 )
			return "tradeId,Error;" + tradeId + ",Unknown pricing engine";

		if(tradeEngineMap.count(cacheName) < 1 )
			return "tradeId,Error;" + tradeId + ",Unknown cache '" + cacheName + "'";

		if(tradeEngineMap[cacheName].count(tradeId) < 1 )
			return "tradeId,Error;" + tradeId + ",Unknown trade '" + tradeId + "'";

		boost::shared_ptr<QuantLib::PricingEngine> engine = pricingEngines[marketName][tradeEngineMap[cacheName][tradeId]];
		if(engine) 
			trade->setPricingEngine(engine);
		
		res << "tradeId," << controlString << ";" << tradeId;
		res << ValueTrade(trade, controlStrings);
	

		return res.str();
	} 
	catch (std::exception& e)
	{
		return e.what();
	} 
	catch (...) 
	{ 
		return "#unknown error";
	}
}

std::string ql::MarketValueTrades(std::string marketName, std::string cacheName, std::string controlString)
{
	try
	{
		std::stringstream res;
		std::vector<std::string> controlStrings = stringToVector(controlString);
		res << "tradeId," << controlString;

		if(caches.count(cacheName) < 1 )
			return "Unknown cache '" + cacheName + "'";

		for each(std::pair<std::string, boost::shared_ptr<QuantLib::Instrument>> kvp in caches[cacheName])
		{
  			res << ";" << kvp.first;
			Instrument* trade = kvp.second.get();

			if(pricingEngines.count(marketName) < 1 )
				return "Unknown pricing engine";
			
			if(tradeEngineMap[cacheName].count(kvp.first) < 1 )
				return "Unknown trade '" + kvp.first + "'";

			boost::shared_ptr<QuantLib::PricingEngine> engine = pricingEngines[marketName][tradeEngineMap[cacheName][kvp.first]];
			if(engine)
				trade->setPricingEngine(engine);

			res << ValueTrade(trade, controlStrings);
		}

		return res.str();
	} 
	catch(std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{
		return "#unknown error";
	}
}

//valuation output more for spreadsheet
std::string ql::ImpliedBlackVol(std::string marketName, std::string volSurfName, std::string modelName)
{
	try
	{
		
		std::vector<boost::shared_ptr<CalibrationHelper>> swaptions = vsurfCalibHelpers[marketName][volSurfName];
		std::vector<QuantLib::Period> periods = vsurfPeriodLabels[marketName][volSurfName];
		std::vector<QuantLib::Period> maturitys = vsurfMaturityLabels[marketName][volSurfName];
		std::vector<double> mktVols = vsurfMarketVols[marketName][volSurfName];

		//Output the implied black volatilities
		int i = 0;
		for each(QuantLib::Period period in periods)
		{
			for each(QuantLib::Period maturity in maturitys)
			{
				Real npv = swaptions[i]->modelValue();
		        Volatility implied = swaptions[i]->impliedVolatility(npv, 1e-4, 1000, 0.05, 0.50);

				std::cout << maturity.length() << "x" << period.length()
		              << std::setprecision(5) << std::noshowpos
		              << ": model " << std::setw(7) << io::volatility(implied)
		              << ", market " << std::setw(7) << io::volatility(mktVols[i])
		              << " (" << std::setw(7) << std::showpos
		              << io::volatility(implied - mktVols[i]) << std::noshowpos << ")\n";

				i++;
			}
	   
		}

		return volSurfName;
	} 
	catch(std::exception& e) 
	{
		return e.what();
	} 
	catch (...) 
	{
		return "#unknown error";
	}

}

std::string ValueTrade(Instrument* trade, std::vector<std::string> controlStrings)
{
	std::string res;
	res = ValueVanillaSwap(trade, controlStrings); if(res != "") return res;
	res = ValueBasisSwap(trade, controlStrings); if(res != "") return res;
	res = ValueSingleFloatingLeg(trade, controlStrings); if(res != "") return res;
	res = ValueSingleFixedLeg(trade, controlStrings); if(res != "") return res;
	res = ValueForwardRateAgreement(trade, controlStrings);	if(res != "") return res;
	res = ValueSwaption(trade, controlStrings); if(res != "") return res;
	res = ValueCreditDefaultSwap(trade, controlStrings); if(res != "") return res;
	res = ValueFixedRateBond(trade, controlStrings); if(res != "") return res;
	res = ValueZeroCouponBond(trade, controlStrings); if(res != "") return res;
	res = ValueFloatingRateBond(trade, controlStrings); if(res != "") return res;
	res = ValueRepo(trade, controlStrings); if(res != "") return res;
	res = ValueUnknown(trade, controlStrings); if(res != "") return res;
	return res;
}

std::string ValueVanillaSwap(Instrument* trade, std::vector<std::string> controlStrings)
{
	std::stringstream res;
	VanillaSwap *vsw = dynamic_cast<VanillaSwap*>(trade); 
	if(vsw)
	{
		for each(std::string s in controlStrings)
		{
			res << ",";
			try
			{
				if(s == "NPV") res << vsw->NPV();
				else if(s == "FairRate") res << vsw->fairRate();
				else if(s == "FixedLegBPS") res << vsw->fixedLegBPS();
				else if(s == "FixedLegNPV") res << vsw->fixedLegNPV();
				else if(s == "FairSpread") res << vsw->fairSpread();
				else if(s == "FloatingLegBPS") res << vsw->floatingLegBPS();
				else if(s == "FloatingLegNPV") res << vsw->floatingLegNPV();
				else res << "N/A";
			}
			catch (std::exception& e) 
			{
				res <<  e.what();
			} 
			catch (...) 
			{
				res <<  "#unknown error";
			}
		}
	}
	return res.str();
}

std::string ValueBasisSwap(Instrument* trade, std::vector<std::string> controlStrings)
{
	std::stringstream res;
	BasisSwap *bsw = dynamic_cast<BasisSwap*>(trade);
	if(bsw)
	{
		for each(std::string s in controlStrings)
		{
			res << ",";
			try
			{
				if(s == "NPV") res << bsw->NPV();
				else if(s == "FairSpread") res << bsw->fairSpread();
				else if(s == "FloatingLegBPS") res << bsw->floatingLegBPS();
				else if(s == "FloatingLegNPV") res << bsw->floatingLegNPV();
				else if(s == "FairSpread2") res << bsw->fairSpread2();
				else if(s == "FloatingLeg2BPS") res << bsw->floatingLeg2BPS();
				else if(s == "FloatingLeg2NPV") res << bsw->floatingLeg2NPV();
				else res << "N/A";
			}
			catch (std::exception& e) 
			{
				res <<  e.what();
			} 
			catch (...) 
			{
				res <<  "#unknown error";
			}
		}
	}
	return res.str();
}

std::string ValueSingleFloatingLeg(Instrument* trade, std::vector<std::string> controlStrings)
{
	std::stringstream res;
	SingleFloatingLeg *flt = dynamic_cast<SingleFloatingLeg*>(trade); 
	if(flt)
	{
		for each(std::string s in controlStrings)
		{
			res << ",";
			try
			{
				if(s == "NPV") res << flt->NPV();
				else if(s == "FairSpread") res << flt->fairSpread();
				else if(s == "FloatingLegBPS") res << flt->floatingLegBPS();
				else if(s == "FloatingLegNPV") res << flt->floatingLegNPV();
				else res << "N/A";
			}
			catch (std::exception& e) 
			{
				res <<  e.what();
			} 
			catch (...) 
			{
				res <<  "#unknown error";
			}
		}
	}
	return res.str();	
}

std::string ValueSingleFixedLeg(Instrument* trade, std::vector<std::string> controlStrings)
{
	std::stringstream res;
	SingleFixedLeg *fxd = dynamic_cast<SingleFixedLeg*>(trade); 
	if(fxd)
	{
		for each(std::string s in controlStrings)
		{
			res << ",";
			try
			{
				if(s == "NPV") res << fxd->NPV();
				else if(s == "FairRate") res << fxd->fairRate();
				else if(s == "FixedLegBPS") res << fxd->fixedLegBPS();
				else if(s == "FixedLegNPV") res << fxd->fixedLegNPV();
				else res << "N/A";
			}
			catch (std::exception& e) 
			{
				res <<  e.what();
			} 
			catch (...) 
			{
				res <<  "#unknown error";
			}
		}
	}
	return res.str();
}

std::string ValueForwardRateAgreement(Instrument* trade, std::vector<std::string> controlStrings)
{
	std::stringstream res;
	ForwardRateAgreement *fra = dynamic_cast<ForwardRateAgreement*>(trade); 
	if(fra)
	{
		for each(std::string s in controlStrings)
		{
			res << ",";
			try
			{
				if(s == "NPV") res << fra->NPV();
				else if(s == "ForwardRate") res << fra->forwardRate();
				else if(s == "SpotValue") res << fra->spotValue();
				else if(s == "ForwardValue") res << fra->forwardValue();
				else res << "N/A";
			}
			catch (std::exception& e) 
			{
				res <<  e.what();
			} 
			catch (...) 
			{
				res <<  "#unknown error";
			}
		}
	}

	return res.str();
}

std::string ValueSwaption(Instrument* trade, std::vector<std::string> controlStrings)
{
	std::stringstream res;
	Swaption *bs = dynamic_cast<Swaption*>(trade); 
	if(bs)
	{
		for each(std::string s in controlStrings)
		{
			res << ",";
			try
			{
				if(s == "NPV") res << bs->NPV();
				else res << "N/A";
			}
			catch (std::exception& e) 
			{
				res <<  e.what();
			} 
			catch (...) 
			{
				res <<  "#unknown error";
			}
		}
	}
	return res.str();
}

std::string ValueCreditDefaultSwap(Instrument* trade, std::vector<std::string> controlStrings)
{
	std::stringstream res;
	CreditDefaultSwap *cds = dynamic_cast<CreditDefaultSwap*>(trade);
	if(cds)
	{
		for each(std::string s in controlStrings)
		{
			res << ",";
			try
			{
				if(s == "NPV") res << cds->NPV();
				else if(s == "FairSpread") res << cds->fairSpread();
				else if(s == "DefaultLegNPV") res << cds->defaultLegNPV();
				else if(s == "CouponLegNPV") res << cds->couponLegNPV();
				else res << "N/A";
			}
			catch (std::exception& e) 
			{
				res <<  e.what();
			} 
			catch (...) 
			{
				res <<  "#unknown error";
			}
		}
	}
	return res.str();
}

std::string ValueFixedRateBond(Instrument* trade, std::vector<std::string> controlStrings)
{
	std::stringstream res;
	FixedRateBondWrap *bnd = dynamic_cast<FixedRateBondWrap*>(trade);
	if(bnd)
	{
		for each(std::string s in controlStrings)
		{
			res << ",";
			try
			{
				if(s == "NPV") res << bnd->NPV();
				else if(s == "CleanPrice") res << bnd->cleanPrice();
				else if(s == "DirtyPrice") res << bnd->dirtyPrice();
				else if(s == "AccruedAmount") res << bnd->accruedAmount();
				else if(s == "PreviousCouponRate") res << bnd->previousCouponRate();
				else if(s == "NextCouponRate") res << bnd->nextCouponRate();
				else if(s == "YieldAct360Annual") res <<bnd->yield(Actual360(),Compounded,Annual);
				else res << "N/A";
			}
			catch (std::exception& e) 
			{
				res <<  e.what();
			} 
			catch (...) 
			{
				res <<  "#unknown error";
			}
		}
	}
	return res.str();
}

std::string ValueZeroCouponBond(Instrument* trade, std::vector<std::string> controlStrings)
{
	std::stringstream res;
	ZeroCouponBondWrap *bnd = dynamic_cast<ZeroCouponBondWrap*>(trade);
	if(bnd)
	{
		for each(std::string s in controlStrings)
		{
			res << ",";
			try
			{
				if(s == "NPV") res << bnd->NPV();
				else if(s == "CleanPrice") res << bnd->cleanPrice();
				else if(s == "DirtyPrice") res << bnd->dirtyPrice();
				else if(s == "AccruedAmount") res << bnd->accruedAmount();
				else if(s == "PreviousCouponRate") res << bnd->previousCouponRate();
				else if(s == "YieldAct360Annual") res <<bnd->yield(Actual360(),Compounded,Annual);
				else res << "N/A";
			}
			catch (std::exception& e) 
			{
				res <<  e.what();
			} 
			catch (...) 
			{
				res <<  "#unknown error";
			}
		}
	}
	return res.str();
}

std::string ValueFloatingRateBond(Instrument* trade, std::vector<std::string> controlStrings)
{
	std::stringstream res;
	FloatingRateBondWrap *bnd = dynamic_cast<FloatingRateBondWrap*>(trade);
	if(bnd)
	{
		for each(std::string s in controlStrings)
		{
			res << ",";
			try
			{
				if(s == "NPV") res << bnd->NPV();
				else if(s == "CleanPrice") res << bnd->cleanPrice();
				else if(s == "DirtyPrice") res << bnd->dirtyPrice();
				else if(s == "AccruedAmount") res << bnd->accruedAmount();
				else if(s == "PreviousCouponRate") res << bnd->previousCouponRate();
				else if(s == "YieldAct360Annual") res <<bnd->yield(Actual360(),Compounded,Annual);
				else res << "N/A";
			}
			catch (std::exception& e) 
			{
				res <<  e.what();
			} 
			catch (...) 
			{
				res <<  "#unknown error";
			}
		}
	}
	return res.str();
}

std::string ValueRepo(Instrument* trade, std::vector<std::string> controlStrings)
{
	std::stringstream res;
	FixedRateBondForwardWrap *repo = dynamic_cast<FixedRateBondForwardWrap*>(trade);
	if(repo)
	{
		for each(std::string s in controlStrings)
		{
			res << ",";
			try
			{
				if(s == "NPV") res << repo->NPV();
				else if(s == "CleanFwdPrice") res << repo->cleanForwardPrice();
				else if(s == "DirtyFwdPrice") res << repo->forwardPrice();
				else if(s == "UnderlyingCleanPrice")  res << repo->underlyingCleanPrice();
				else if(s == "UnderlyingDirtyPrice")  res << repo->underlyingDirtyPrice();
				else if(s == "UnderlyingSettlementAccrued")  res << repo->underlyingAccruedAmount(repo->settlementDate());
				else if(s == "UnderlyingDeliveryAccrued")  res << repo->underlyingAccruedAmount(repo->deliveryDate());
				else if(s == "UnderlyingSpotIncome")  res << repo->income();
				else if(s == "UnderlyingFwdIncome")  res << repo->income()/repo->discountCurve()->discount(repo->deliveryDate());
				else if(s == "Strike") res << repo->price();
				else if(s == "ImpliedYield") res << repo->impliedYield(repo->underlyingDirtyPrice(), repo->price(), repo->settlementDate(), Simple, repo->dayCounter());
				else if(s == "MktRepoRate") res << repo->discountCurve()->zeroRate(repo->deliveryDate(), repo->dayCounter(), Simple, Annual);
				else res << "N/A";
			}
			catch (std::exception& e) 
			{
				res <<  e.what();
			} 
			catch (...) 
			{
				res <<  "#unknown error";
			}
		}
	}
	return res.str();
}

std::string ValueUnknown(Instrument* trade, std::vector<std::string> controlStrings)
{
	std::stringstream res;
	for each(std::string s in controlStrings)
	{
		res << ",";
		try
		{
			if(s == "NPV") res << trade->NPV();
			else res << "N/A";
		}
		catch (std::exception& e) 
		{
			res <<  e.what();
		} 
		catch (...) 
		{
			res <<  "#unknown error";
		}
	}
	return res.str();
}

